Skip to content

[OTLP] Add support for GZip compression#7055

Merged
martincostello merged 21 commits intoopen-telemetry:mainfrom
martincostello:gh-3961
Apr 28, 2026
Merged

[OTLP] Add support for GZip compression#7055
martincostello merged 21 commits intoopen-telemetry:mainfrom
martincostello:gh-3961

Conversation

@martincostello
Copy link
Copy Markdown
Member

@martincostello martincostello commented Apr 10, 2026

Fixes #3961

Changes

Add support for GZip compression to the OTLP exporter.

Continues the work started in #6494.

Once released, should also update the compliance matrix.

Merge requirement checklist

  • CONTRIBUTING guidelines followed (license requirements, nullable enabled, static analysis, etc.)
  • Unit tests added/updated
  • Appropriate CHANGELOG.md files updated for non-trivial changes
  • Changes in public API reviewed (if applicable)

@github-actions github-actions Bot added the pkg:OpenTelemetry.Exporter.OpenTelemetryProtocol Issues related to OpenTelemetry.Exporter.OpenTelemetryProtocol NuGet package label Apr 10, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 10, 2026

Codecov Report

❌ Patch coverage is 98.18182% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.51%. Comparing base (805a2a8) to head (04349f2).
⚠️ Report is 3 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
.../Implementation/ExportClient/PooledBufferStream.cs 97.27% 4 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #7055      +/-   ##
==========================================
+ Coverage   89.26%   89.51%   +0.25%     
==========================================
  Files         271      272       +1     
  Lines       13088    13296     +208     
==========================================
+ Hits        11683    11902     +219     
+ Misses       1405     1394      -11     
Flag Coverage Δ
unittests-Project-Experimental 89.39% <98.18%> (+0.20%) ⬆️
unittests-Project-Stable 89.39% <98.18%> (+0.22%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...ol/Implementation/ExportClient/OtlpExportClient.cs 100.00% <100.00%> (ø)
...mplementation/ExportClient/OtlpGrpcExportClient.cs 79.31% <100.00%> (+4.57%) ⬆️
...mplementation/ExportClient/OtlpHttpExportClient.cs 100.00% <100.00%> (ø)
...tation/OpenTelemetryProtocolExporterEventSource.cs 57.50% <100.00%> (+1.08%) ⬆️
...orter.OpenTelemetryProtocol/OtlpExporterOptions.cs 99.37% <100.00%> (+0.09%) ⬆️
.../Implementation/ExportClient/PooledBufferStream.cs 97.27% <97.27%> (ø)

... and 8 files with indirect coverage changes

@martincostello martincostello marked this pull request as ready for review April 10, 2026 14:34
@martincostello martincostello requested a review from a team as a code owner April 10, 2026 14:34
Copilot AI review requested due to automatic review settings April 10, 2026 14:34
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds configurable gzip compression support to the OTLP exporter to align with the OTLP exporter specification (including env var configuration) and validates behavior via new/updated unit tests.

Changes:

  • Introduces OtlpExportCompression and OtlpExporterOptions.Compression, with spec env var support (OTEL_EXPORTER_OTLP*_COMPRESSION).
  • Implements gzip request compression for OTLP over HTTP and gRPC export clients.
  • Adds/updates unit tests and updates changelog + public API tracking files.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpSpecConfigDefinitionTests.cs Extends spec config test data and assertions to include compression env vars.
test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpHttpExportClientTests.cs Adds HTTP export tests validating payload and headers with/without gzip.
test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpGrpcExportClientTests.cs Adds gRPC export tests validating compressed framing and decompression behavior.
test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterOptionsTests.cs Extends options/config tests to cover compression env var parsing and invalid values.
src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs Adds Compression option, parsing helper, and spec-env-var application.
src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExportCompression.cs New public enum defining supported compression modes.
src/OpenTelemetry.Exporter.OpenTelemetryProtocol/IOtlpExporterOptions.cs Adds Compression to internal options contract.
src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OtlpSpecConfigDefinitions.cs Adds spec env var constants for compression across signals.
src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/OtlpHttpExportClient.cs Implements gzip compression for HTTP request content.
src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/OtlpGrpcExportClient.cs Implements gzip compression for gRPC framing + request header.
src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/OtlpExportClient.cs Centralizes content creation via overridable method; wires CompressionEnabled.
src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md Documents new opt-in gzip compression configuration.
src/OpenTelemetry.Exporter.OpenTelemetryProtocol/.publicApi/Stable/PublicAPI.Unshipped.txt Tracks new public API surface (OtlpExportCompression, OtlpExporterOptions.Compression).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs Outdated
Comment thread src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptions.cs Outdated
martincostello and others added 4 commits April 13, 2026 15:26
Add support for GZip compression to the OTLP exporter.

Picks up from open-telemetry#6494.

Resolves open-telemetry#3961.

Co-Authored-By: Hannah Haering <157852144+hannahhaering@users.noreply.github.com>
- Avoid allocating a buffer for every write of compressed gRPC data.
- Simplify `IsTransientNetworkError()`.
Add coverage for different ways to specify the compression value.
- Ensure only one `grpc-encoding` header.
- Remove redundant null checks.
Remove trailing spaces.
Add missing blank line.

* Added opt-in support for gzip compression. Compression can be configured
programmatically via the new `OtlpExporterOptions.Compression` property,
or through the environment variables such as `OTEL_EXPORTER_OTLP_COMPRESSION=gzip`.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: maybe mention the signal specific env vars too here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, if we can update the OTLP's readme also, that'd better.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point - I forgot about the README.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

README updated.

return base.CreateHttpContent(buffer, contentLength);
}

var compressedStream = new MemoryStream();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets leave a todo for a future optimization to see if we can avoid allocation by renting/pooling arrays.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What specifically were you thinking of?

  • Renting a buffer to pass into the MemoryStream?
  • Renting a single shared buffer (like the main exporter does) for compression and re-using it across requests to pass into the MemoryStream?
  • A custom Stream implementation that acts like a memory stream but is backed by rented buffers?
  • Something else?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've got an implementation of the third option locally, I'm just testing it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We wouldn't be able to take a dependency on those.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't recommend that for this library either.

But it has quite a few with unit tests.

I don't see a problem grabbing the code from one that fits here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took a quick look, and didn't see an "obvious" one that grabbed from the array pool, plus they seemed to have a bunch of extra interfaces I'd have to prune out. As I'd already written an implementation when you commented, I'll stick with that unless there's a compelling reason to replace it with something adapted and vendored from there.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops! I meant to leave a TODO for revisiting this in a future PR to keep the initial version easier to review. My suggestion is to avoid the optimization in this PR, so review can focus on just the feature, and then a follow up where we can focus on pooling/efficiency part!

Sorry I was not very clear initially!

Copy link
Copy Markdown
Member Author

@martincostello martincostello Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I've already done the work either I can remove it and just immediately open a PR as a draft that's the same plus 2 extra files to rebase later and then re-run the benchmarks without the optimization, or we can just leave it in.

Log the compressed and uncompressed sizes when using GZip.
Add an implementation of `Stream` that uses pooled buffers.
Rename to `GZip` to match `GZipStream`.
Add documentation for compression.
Add a benchmark for OTLP compression.
@github-actions github-actions Bot added the perf Performance related label Apr 27, 2026
@martincostello
Copy link
Copy Markdown
Member Author

martincostello commented Apr 27, 2026

Benchmark results


BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.8246/25H2/2025Update/HudsonValley2)
13th Gen Intel Core i7-13700H 2.90GHz, 1 CPU, 20 logical and 14 physical cores
.NET SDK 10.0.203
  [Host]               : .NET 10.0.7 (10.0.7, 10.0.726.21808), X64 RyuJIT x86-64-v3
  .NET 10.0            : .NET 10.0.7 (10.0.7, 10.0.726.21808), X64 RyuJIT x86-64-v3
  .NET Framework 4.6.2 : .NET Framework 4.8.1 (4.8.9325.0), X64 RyuJIT VectorSize=256


Method Job Runtime Compression Mean Error StdDev Median Ratio RatioSD Allocated Alloc Ratio
OtlpExporter_Compression .NET 10.0 .NET 10.0 None 7.260 ms 0.1886 ms 0.5531 ms 7.075 ms 1.01 0.10 3.44 KB 1.00
OtlpExporter_Compression .NET Framework 4.6.2 .NET Framework 4.6.2 None 18.818 ms 0.3736 ms 0.6444 ms 18.802 ms 2.61 0.21 6 KB 1.75
OtlpExporter_Compression .NET 10.0 .NET 10.0 GZip 8.259 ms 0.1643 ms 0.2920 ms 8.248 ms 1.00 0.05 4.08 KB 1.00
OtlpExporter_Compression .NET Framework 4.6.2 .NET Framework 4.6.2 GZip 40.743 ms 0.7962 ms 1.0070 ms 40.911 ms 4.94 0.21 136.59 KB 33.49

Stub-out the `HttpClient` requests.
Use a top-level program for benchmarks and return whether they have succeeded to the caller.
`Stream.CanTimeout` is already `false`.
Add coverage for `PooledBufferStream` that isn't already covered by other tests.
Rename `buf` to `rented` and fix trying to return an empty buffer.
Log the compression type in the event source.
Comment thread src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md Outdated
Update PR number.
@martincostello martincostello added this pull request to the merge queue Apr 28, 2026
Merged via the queue into open-telemetry:main with commit 6232fb2 Apr 28, 2026
60 checks passed
@martincostello martincostello deleted the gh-3961 branch April 28, 2026 10:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

perf Performance related pkg:OpenTelemetry.Exporter.OpenTelemetryProtocol Issues related to OpenTelemetry.Exporter.OpenTelemetryProtocol NuGet package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Exporter.OpenTelemetryProtocol] Support for Compression

5 participants